package com.ruoyi.bus.wechat;

import com.ejlchina.okhttps.GsonMsgConvertor;
import com.ejlchina.okhttps.HTTP;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.system.service.ISysConfigService;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Date;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @Description 微信Token处理工具
 * @Author caiyanshan
 * @Date 2021/4/2 10:50
 * @Param
 * @Return
 */
@Slf4j
public class WechatTokenUtils {
  
  private static RedisCache redis;
  
  private static ISysConfigService iSysConfigService;
  
  private static ISysConfigService getSysConfig(){
    if(iSysConfigService == null){
      iSysConfigService = SpringUtils.getBean(ISysConfigService.class);
    }
    return iSysConfigService;
  }
  
  private static RedisCache getRedisCache(){
    if(redis == null){
      redis = SpringUtils.getBean(RedisCache.class);
    }
    return redis;
  }
  
  private static final String BaseUrl = "https://api.weixin.qq.com/cgi-bin/token?";
  
  private static final String Token_Url = "grant_type=client_credential";
  
  private static Lock lock = new ReentrantLock();
  
  private static HTTP wechatHttp = null;
  
  /**
   * @Description 设置基础Http配置
   * @Author caiyanshan
   * @Param []
   * @Return com.ejlchina.okhttps.HTTP
   */
  private static HTTP getHandleHttp(){
    if(wechatHttp == null){
      wechatHttp = HTTP.builder().baseUrl(BaseUrl)
              .addMsgConvertor(new GsonMsgConvertor())
              .build();
    }
    return wechatHttp;
  }
  
  /**
   * @Description 获取微信token
   * 有效期目前为 2 个小时，需定时刷新，重复获取将导致上次获取的 access_token 失效。
   * 当前时间减掉token获取时间小于2小时，即为有效。
   * @Author caiyanshan
   * @Param []
   * @Return java.lang.String
   */
  public static String getAccessToken(Integer type){
    String appId = getSysConfig().selectConfigByKey("wechat.appId." + type);
    String secret = getSysConfig().selectConfigByKey("wechat.appSecret." + type);
    AccessToken token = null;
    try{
      lock.lock();
      String key = "WechatToken:" + appId;
      token = getRedisCache().getCacheObject(key);
      if(token == null){//数据为空要重新获取
        token = handleToken(appId, secret);
        log.info("首次获取token数据，结果为:" + token.getToken());
        getRedisCache().setCacheObject(key, token, 60, TimeUnit.MINUTES);
        return token.getToken();
      }
      if(token.isExpire()){ // 过期，重新获取
        token = handleToken(appId, secret);
        log.info("token数据已过期，再次获取数据结果为:" + token.getToken());
        getRedisCache().setCacheObject(key, token, 60, TimeUnit.MINUTES);
        return token.getToken();
      }
    }finally {
      lock.unlock();//必须解锁
    }
    log.info("缓存中获取token,数据为:" + token.getToken());
    return token.getToken();
  }
  
  /**
   * @Description 发送请求获取token
   * @Author caiyanshan
   * @Date 2020/10/16 10:55
   * @Param []
   * @Return
   */
  private static AccessToken handleToken(String appId, String secret) {
    AccessToken result = getHandleHttp().sync(Token_Url).addUrlPara("appid",appId)
            .addUrlPara("secret", secret).get().getBody().cache().toBean(AccessToken.class);
    log.info("本次请求微信的token结果为: " +result);
    result.setStartTime(new Date());//重新获取需复制开始时间
    return result;
  }
  
}
